#include "sdlengine.h"

SDLEngine::SDLEngine() {
    m_lLastTick = 0;
    m_iWidth = 896;
    m_iHeight = 672;
    m_czTitle = 0;
    m_pScreen = 0;
    m_iFPSTickCounter = 0;
    m_iFPSCounter = 0;
    m_iCurrentFPS = 0;
    m_bMinimized = false;
    m_uiMaxFPS = 50;
}

SDLEngine::~SDLEngine() {
    SDL_Quit();
}

void SDLEngine::SetSize(const int& iWidth,
        const int& iHeight,
        bool bFullscreen = false) {
    m_iWidth = iWidth;
    m_iHeight = iHeight;
    int i_flags = SDL_SWSURFACE;
    if(bFullscreen) i_flags |= SDL_FULLSCREEN;
    m_bFullscreen = bFullscreen;
    m_pScreen = SDL_SetVideoMode(iWidth, iHeight, 0, i_flags);
}

void SDLEngine::ToggleFullscreen() {
    if(m_bFullscreen)
        SetSize(m_iWidth, m_iHeight, false);
    else
        SetSize(m_iWidth, m_iHeight, true);
}

void SDLEngine::Init() {
    atexit(SDL_Quit);

    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
        fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError());
        exit(1);
    }

    SetSize(m_iWidth, m_iHeight);

    if (m_pScreen == NULL) {
        fprintf(stderr, "Unable to set up video: %s\n", SDL_GetError());
        exit(1);
    }

    AdditionalInit();
}

void SDLEngine::Start() {
    m_lLastTick = SDL_GetTicks();
    m_bQuit = false;

    while (!m_bQuit) {
        HandleInput();

        if (m_bMinimized) {
            // Release some system resources if the app. is minimized.
            m_lLastTick = SDL_GetTicks();
        } else {
            DoThink();
            DoRender();
        }

        if (m_uiMaxFPS > 0) {
            long iElapsedTicks = SDL_GetTicks() - m_lLastTick;
            if (iElapsedTicks < 1000 / m_uiMaxFPS)
                SDL_Delay((1000 / m_uiMaxFPS) - iElapsedTicks);
        }
    }

    End();
}

void SDLEngine::Stop() {
    m_bQuit = true;
}

/** Handles all controller inputs.
        @remark This function is called once per frame.
 **/
void SDLEngine::HandleInput() {
    // Poll for events, and handle the ones we care about.
    SDL_Event event;
    while (SDL_PollEvent(&event)) {
        switch (event.type) {
            case SDL_KEYDOWN:
                // If escape is pressed set the Quit-flag
                if (event.key.keysym.sym == SDLK_ESCAPE) {
                    m_bQuit = true;
                    break;
                }

                KeyDown(event.key.keysym.sym);
                break;

            case SDL_KEYUP:
                KeyUp(event.key.keysym.sym);
                break;

            case SDL_QUIT:
                m_bQuit = true;
                break;

            case SDL_MOUSEMOTION:
                MouseMoved(
                        event.button.button,
                        event.motion.x,
                        event.motion.y,
                        event.motion.xrel,
                        event.motion.yrel);
                break;

            case SDL_MOUSEBUTTONUP:
                MouseButtonUp(
                        event.button.button,
                        event.motion.x,
                        event.motion.y,
                        event.motion.xrel,
                        event.motion.yrel);
                break;

            case SDL_MOUSEBUTTONDOWN:
                MouseButtonDown(
                        event.button.button,
                        event.motion.x,
                        event.motion.y,
                        event.motion.xrel,
                        event.motion.yrel);
                break;

            case SDL_ACTIVEEVENT:
                if (event.active.state & SDL_APPACTIVE) {
                    if (event.active.gain) {
                        m_bMinimized = false;
                        WindowActive();
                    } else {
                        m_bMinimized = true;
                        WindowInactive();
                    }
                }
                break;
        } // switch
    } // while (handling input)
}

/** Handles the updating routine. **/
void SDLEngine::DoThink() {
    long iElapsedTicks = SDL_GetTicks() - m_lLastTick;
    m_lLastTick = SDL_GetTicks();

    Think(iElapsedTicks);

    m_iFPSTickCounter += iElapsedTicks;
}

/** Handles the rendering and FPS calculations. **/
void SDLEngine::DoRender() {

    ++m_iFPSCounter;

    if (m_iFPSTickCounter >= 1000) {
        m_iCurrentFPS = m_iFPSCounter;
        m_iFPSCounter = 0;
        m_iFPSTickCounter = 0;
    }


    SDL_FillRect(m_pScreen, 0, SDL_MapRGB(m_pScreen->format, 0, 0, 0));

    // Lock surface if needed
    if (SDL_MUSTLOCK(m_pScreen))
        if (SDL_LockSurface(m_pScreen) < 0)
            return;

    Render(GetSurface());

    // Unlock if needed
    if (SDL_MUSTLOCK(m_pScreen))
        SDL_UnlockSurface(m_pScreen);

    // Tell SDL to update the whole gScreen
    SDL_Flip(m_pScreen);
}

void SDLEngine::SetMaxFPS(unsigned int uiMaxFPS) {
    m_uiMaxFPS = uiMaxFPS;
}

void SDLEngine::SetTitle(const char* czTitle) {
    m_czTitle = czTitle;
    SDL_WM_SetCaption(czTitle, 0);
}

const char* SDLEngine::GetTitle() {
    return m_czTitle;
}

SDL_Surface* SDLEngine::GetSurface() {
    return m_pScreen;
}

int SDLEngine::GetFPS() {
    return m_iCurrentFPS;
}

